package cn.ekuma.data.dao.user.tree;

import java.awt.Component;
import java.util.Comparator;
import java.util.EventListener;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.event.EventListenerList;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import cn.ekuma.data.dao.I_DataLogic;
import cn.ekuma.data.dao.bean.AppLoger;
import cn.ekuma.data.dao.bean.I_Category;
import cn.ekuma.data.dao.user.tree.BrowsableTreeDataModel.CategoryTreeNode;
import cn.ekuma.data.log.DataLogicLoger;
import cn.ekuma.data.ui.swing.SwingEditorRecord;

import com.openbravo.data.basic.BasicException;
import com.openbravo.data.loader.LocalRes;
import com.openbravo.data.user.BrowseListener;
import com.openbravo.data.user.DirtyManager;
import com.openbravo.data.user.EditorCreator;
import com.openbravo.data.user.EditorListener;
import com.openbravo.data.user.Finder;
import com.openbravo.data.user.I_BrowsableTreeEditableData;
import com.openbravo.data.user.StateListener;

public class BrowsableEditableTreeDataModel implements I_BrowsableTreeEditableData<I_Category>{

	private final static int INX_EOF = -1;

    private BrowsableTreeDataModel m_bd;

    protected EventListenerList listeners = new EventListenerList();

    private SwingEditorRecord<I_Category> m_editorrecord;
    private DirtyManager m_Dirty;
    private int m_iState; // vinculado siempre al m_editorrecord

    private CategoryTreeNode selectedObj;

    private boolean iseditable = true;

	private int m_iIndex;

	private boolean m_bIsAdjusting;
	
    /** Creates a new instance of BrowsableEditableData */
    public BrowsableEditableTreeDataModel(BrowsableTreeDataModel bd, SwingEditorRecord ed, DirtyManager dirty) {
        m_bd = bd;

        m_editorrecord = ed;
        m_Dirty = dirty;
        m_iState = ST_NORECORD;
        m_iIndex = INX_EOF; // En EOF
        m_bIsAdjusting = false;

        // Inicializo ?
        m_editorrecord.writeValueEOF();
        m_Dirty.setDirty(false);
    }

    public BrowsableEditableTreeDataModel(I_DataLogic dataLogic,Class cl, Comparator c, SwingEditorRecord ed, DirtyManager dirty,EditorCreator filterCreator) {
        this(new BrowsableTreeDataModel(dataLogic, cl, c , filterCreator), ed, dirty);
    }

    public BrowsableEditableTreeDataModel(I_DataLogic dataLogic,Class cl, Comparator c, SwingEditorRecord ed, DirtyManager dirty) {
        this(new BrowsableTreeDataModel(dataLogic, cl, c), ed, dirty);
    }

    public BrowsableEditableTreeDataModel(I_DataLogic dataLogic,Class cl, SwingEditorRecord ed, DirtyManager dirty,EditorCreator filterCreator) {
        this(new BrowsableTreeDataModel(dataLogic, cl, filterCreator), ed, dirty);
    }

    public BrowsableEditableTreeDataModel(I_DataLogic dataLogic,Class cl, SwingEditorRecord ed, DirtyManager dirty) {
        this(new BrowsableTreeDataModel(dataLogic, cl), ed, dirty);
    }
    
    public final TreeModel getTreeModel(){
    	return m_bd;
    }
   
    public final boolean isAdjusting() {
        return m_bIsAdjusting ;
    }

    public final I_Category getCurrentElement() {
        return selectedObj!=null?selectedObj.getCategory():null;
    }
    public final int getIndex() {
        return m_iIndex;
    }

    public final void addStateListener(StateListener l) {
        listeners.add(StateListener.class, l);
    }
    public final void removeStateListener(StateListener l) {
        listeners.remove(StateListener.class, l);
    }
    public final void addEditorListener(EditorListener l) {
        listeners.add(EditorListener.class, l);
    }
    public final void removeEditorListener(EditorListener l) {
        listeners.remove(EditorListener.class, l);
    }

    public final void addBrowseListener(BrowseListener l) {
        listeners.add(BrowseListener.class, l);
    }
    public final void removeBrowseListener(BrowseListener l) {
        listeners.remove(BrowseListener.class, l);
    }

    public int getState() {
        return m_iState;
    }

    private void fireStateUpdate() {
        EventListener[] l = listeners.getListeners(StateListener.class);
        int iState = getState();
        for (int i = 0; i < l.length; i++) {
            ((StateListener) l[i]).updateState(iState);
        }
    }
    protected void fireDataBrowse() {

        m_bIsAdjusting = true;
        // Lanzamos los eventos...
        I_Category obj = getCurrentElement();

        // actualizo el registro
        if (obj == null) {
            m_iState = ST_NORECORD;
            m_editorrecord.writeValueEOF();
        } else {
            m_iState = ST_UPDATE;
            m_editorrecord.writeValueEdit(obj);
        }
        m_Dirty.setDirty(false);
        fireStateUpdate();

        // Invoco a los Editor Listener
        EventListener[] l = listeners.getListeners(EditorListener.class);
        for (int i = 0; i < l.length; i++) {
            ((EditorListener) l[i]).updateValue(obj);
        }
        m_bIsAdjusting = false;
    }

    
    public boolean canLoadData() {
        return m_bd.canLoadData();
    }

    public void setEditable(boolean value) {
        iseditable = value;
    }

    public boolean canInsertData() {
        return iseditable && m_bd.canInsertData();
    }

    public boolean canDeleteData() {
        return iseditable && m_bd.canDeleteData();
    }

    public boolean canUpdateData() {
        return iseditable && m_bd.canUpdateData();
    }

    public void refreshCurrent() {
    }
    
    public void refreshData() throws BasicException {
        saveData();
        m_bd.refreshData();
        m_editorrecord.refresh();
        selectedObj=null;
        fireDataBrowse();
        
    }
    public void loadData() throws BasicException {
        saveData();
        m_bd.loadData();
        m_editorrecord.refresh();
        selectedObj=null;
        fireDataBrowse();
    }
    public void unloadData() throws BasicException {
        saveData();
        m_bd.unloadData();
        m_editorrecord.refresh();
        selectedObj=null;
        fireDataBrowse();
    }

    public void sort(Comparator c) throws BasicException {
    }

    public void moveTo(int i) throws BasicException {
    }
    
    public void moveTo(TreePath path) throws BasicException {
    	selectedObj=(CategoryTreeNode) path.getLastPathComponent();
        fireDataBrowse();
    }

    public final void movePrev() throws BasicException {
        
    }
    public final void moveNext() throws BasicException {
        
    }
    public final void moveFirst() throws BasicException {
        
    }
    public final void moveLast() throws BasicException {
       
    }
    public final int findNext(Finder f) throws BasicException {
        return m_bd.findNext(m_iIndex, f);
    }
    
    public void saveData() throws BasicException {
        if (m_Dirty.isDirty()) {
            if (m_iState == ST_UPDATE) { 
            	 int index=selectedObj.getParent().getIndex(selectedObj);
            	 I_Category obj=m_editorrecord.createValue();
            	 m_bd.updateRecord(selectedObj, obj,index);
                 if(m_editorrecord.isLogAble()&&DataLogicLoger.isLogAble()){
                	 AppLoger objLoger=new AppLoger();
                	 objLoger.setObjClass(obj.getClass().getName());
                	 objLoger.setObjId(obj.getID());
                	 objLoger.setType(DataLogicLoger.BEAN_Update);
                	 objLoger.setChangeValue(m_editorrecord.getLogerString());
                	 DataLogicLoger.log(objLoger);
                 }	
                 m_editorrecord.refresh(); 
                 fireDataBrowse();
            } else if (m_iState == ST_INSERT) {
            	I_Category obj=m_editorrecord.createValue();
                m_bd.insertRecord(obj);
                if(m_editorrecord.isLogAble()&&DataLogicLoger.isLogAble()){
               	 AppLoger objLoger=new AppLoger();
               	 objLoger.setObjClass(obj.getClass().getName());
               	 objLoger.setObjId(obj.getID());
               	 objLoger.setType(DataLogicLoger.BEAN_Insert);
               	 objLoger.setChangeValue(m_editorrecord.getLogerString());
               	 DataLogicLoger.log(objLoger);
                 }	
                m_editorrecord.refresh();
                fireDataBrowse();
            } else if (m_iState == ST_DELETE) {
            	I_Category obj=m_editorrecord.createValue();
                m_bd.removeRecord(selectedObj);
                if(m_editorrecord.isLogAble()&&DataLogicLoger.isLogAble()){
                  	 AppLoger objLoger=new AppLoger();
                  	 objLoger.setObjClass(obj.getClass().getName());
                  	 objLoger.setObjId(obj.getID());
                  	 objLoger.setType(DataLogicLoger.BEAN_Delete);
                  	 DataLogicLoger.log(objLoger);
                 }
                m_editorrecord.refresh();
                selectedObj=null;
                fireDataBrowse();
            } // queda ST_NORECORD
        }
    }

    public void actionReloadCurrent(Component c) {
        if (!m_Dirty.isDirty() ||
                JOptionPane.showConfirmDialog(c, LocalRes.getIntString("message.changeslost"), LocalRes.getIntString("title.editor"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
            refreshCurrent();
        }
    }

    public boolean actionClosingForm(Component c) throws BasicException {
        if (m_Dirty.isDirty()) {
            int res = JOptionPane.showConfirmDialog(c, LocalRes.getIntString("message.wannasave"), LocalRes.getIntString("title.editor"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
            if (res == JOptionPane.YES_OPTION) {
                saveData();
                return true;
            } else if (res == JOptionPane.NO_OPTION) {
                refreshCurrent();
                return true;
            } else {
                return false;
            }
        } else {
            return true;
        }
    }

    /*
     * Metodos publicos finales (algunos protegidos que podrian ser finales
     */

    public final void actionLoad() throws BasicException {
        loadData();
    }

    public final void actionInsert() throws BasicException {
        // primero persistimos
        saveData();

        if (canInsertData()) {
            // Y nos ponemos en estado de insert
            m_iState = ST_INSERT;
            m_editorrecord.writeValueInsert(null);
            m_Dirty.setDirty(false);
            fireStateUpdate(); // ?
        }
    }

    public final void actionDelete() throws BasicException {
        // primero persistimos
        saveData();

        if (canDeleteData()) {
            // Y nos ponemos en estado de delete
        	I_Category obj = getCurrentElement();
            if (obj!=null) {
                m_iState = ST_DELETE;
                m_editorrecord.writeValueDelete(obj);
                m_Dirty.setDirty(true);
                fireStateUpdate(); // ?
            }
        }
    }

    private final void baseMoveTo(int i) {
        fireDataBrowse();
    }

	public CategoryTreeNode getSelectedObj() {
		return selectedObj;
	}
   
	public TreePath getCurrentTreePath(){
		return new TreePath(m_bd.getPathToRoot(selectedObj));
	}

	@Override
	public void loadData(List<I_Category> datas) throws BasicException {
		saveData();
        m_bd.loadList(datas);
        m_editorrecord.refresh();
        selectedObj=null;
        fireDataBrowse();
		
	}
	
}
